package com.lamb.script.core.utils;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;

/**
 * toString 方法.
 *
 * @author : lamb
 * @version : 1.0
 * @date :  2019-08-02 18:19
 **/
public class ScriptUtil {

    /**
     * js脚本内容.
     */
    public static final String FLAG_JS_CONTENT = "@js:";

    /**
     * 文件协议.
     */
    private static final String PROTOCOL_FILE = "file";
    private static final String CLASSPATH_STR = "classpath:";
    private static final String PREFIX_SLASH = "/";
    private static final String HTTP = "http";
    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    /**
     * string 转 byte[].默认.
     *
     * @param src 内容.
     */
    public static byte[] getBytes(String src) {
        if (null == src) {
            return null;
        }
        return src.getBytes(DEFAULT_CHARSET);
    }

    /**
     * toString.
     *
     * @param bytes bytes.
     * @return string.
     */
    public static String toString(byte[] bytes) {
        return new String(bytes, DEFAULT_CHARSET);
    }

    /**
     * 是否为空.
     *
     * @param str 字符串.
     * @return 是否为空.
     */
    public static boolean isBlank(String str) {
        return null == str || str.trim().length() == 0;
    }

    /**
     * 创建一个数据.
     *
     * @param length 数据长度.
     */
    public static Object[] newArray(int length) {
        return new Object[length];
    }

    /**
     * 优雅关闭.
     *
     * @param autoCloseable 可关闭工具类.
     */
    public static void closeQuietly(AutoCloseable autoCloseable) {
        if (null != autoCloseable) {
            try {
                autoCloseable.close();
            } catch (Exception ignored) {
            }
        }
    }

    /**
     * 文件读取.
     *
     * @param fileName 文件名.
     * @return bytes.
     * @throws IOException 异常.
     */
    public static byte[] readToByteBuffer(String fileName) throws IOException {
        URL url = getFileEveryWhere(fileName);
        if (null == url) {
            throw new FileNotFoundException(fileName);
        }
        if (PROTOCOL_FILE.equalsIgnoreCase(url.getProtocol())) {
            try {
                return readToByteBuffer(new File(url.toURI()));
            } catch (URISyntaxException e) {
                throw new IOException(e);
            }
        }
        try (InputStream inStream = url.openStream()) {
            return readToByteBuffer(inStream);
        }
    }

    /**
     * 读取文件.
     *
     * @param file 文件.
     * @return bytes.
     * @throws IOException 异常.
     */
    public static byte[] readToByteBuffer(File file) throws IOException {
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在");
        }
        BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(file));
        try {
            return readToByteBufferByLength(inStream, (int) file.length());
        } finally {
            closeQuietly(inStream);
        }
    }

    /**
     * 读取文件.
     *
     * @param inStream in.
     * @param maxSize  最多读取多少.
     * @return bytes.
     * @throws IOException 异常.
     */
    public static byte[] readToByteBuffer(InputStream inStream, int maxSize) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        if (maxSize > 0) {
            int bufferSize = 0x2000;
            if (bufferSize > maxSize) {
                bufferSize = maxSize;
            }
            byte[] buffer = new byte[bufferSize];
            int read;
            int remaining = maxSize;

            while (true) {
                read = inStream.read(buffer);
                if (-1 == read) {
                    break;
                }
                if (read > remaining) {
                    outStream.write(buffer, 0, read);
                    break;
                }
                remaining -= read;
                outStream.write(buffer, 0, read);
                if (remaining <= 0) {
                    break;
                }
                if (bufferSize > read && inStream.available() == 0) {
                    break;
                }
            }
        }
        return outStream.size() > 0 ? outStream.toByteArray() : null;
    }

    /**
     * 读取数据.
     *
     * @param inStream in.
     * @return bytes.
     * @throws IOException 异常.
     */
    public static byte[] readToByteBuffer(InputStream inStream) throws IOException {
        return readToByteBuffer(inStream, 1024 * 1024);
    }

    /**
     * 查找文件.
     *
     * @param path 路径.
     * @return 文件uri.
     */
    public static URL getFileEveryWhere(String path) {
        if (path.startsWith(CLASSPATH_STR)) {
            path = path.substring(CLASSPATH_STR.length());
            if (path.startsWith(PREFIX_SLASH)) {
                path = path.substring(1);
            }
            URL rs = Thread.currentThread().getContextClassLoader().getResource(path);
            if (null != rs) {
                return rs;
            }
            return null;
        }
        if (path.startsWith(HTTP)) {
            try {
                return new URL(path);
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }
        }
        File f = new File(path);
        try {
            if (f.exists()) {
                return f.toURI().toURL();
            }
            f = new File(System.getProperty("user.dir") + PREFIX_SLASH + path);
            if (f.exists()) {
                return f.toURI().toURL();
            }
        } catch (MalformedURLException ignored) {
        }
        return null;
    }

    /**
     * 读取指定长度的数据.
     *
     * @param inStream in.
     * @param length   长度.
     * @return bytes.
     * @throws IOException 异常.
     */
    public static byte[] readToByteBufferByLength(InputStream inStream, int length) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        if (length > 0) {
            int bufferSize = 0x2000;
            byte[] buffer = new byte[bufferSize];
            int read;
            int remaining = length;

            while (remaining > 0) {
                if (remaining < bufferSize) {
                    buffer = new byte[remaining];
                }
                read = inStream.read(buffer);
                if (-1 == read) {
                    break;
                }
                remaining -= read;
                outStream.write(buffer, 0, read);
            }
        }
        return outStream.size() > 0 ? outStream.toByteArray() : null;
    }

    /**
     * 程序休眠处理.
     *
     * @param ms 毫秒时间.
     */
    public static void sleep(long ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException ignored) {
        }
    }

    /**
     * 写入文件.
     *
     * @param filePath      文件地址.
     * @param data          数据.
     * @param scriptConsole scriptConsole.
     * @return 是否写入成功.
     */
    public static boolean writeFile(String filePath, byte[] data, ScriptConsole scriptConsole) {
        if (isBlank(filePath) || null == data) {
            return false;
        }
        File file = new File(filePath);
        if (null == file.getParent()) {
            file = new File(file.getAbsolutePath());
        }
        if (!file.getParentFile().exists()) {
            boolean mkDirs = file.getParentFile().mkdirs();
            if (!mkDirs) {
                scriptConsole.info("writeFile failed, create parentFile error.");
                return false;
            }
        }
        try (OutputStream out = new FileOutputStream(file)) {
            out.write(data);
            out.flush();
            return true;
        } catch (Exception e) {
            scriptConsole.info("writeFile failed, path = " + filePath + ", msg = " + e.getLocalizedMessage());
            e.printStackTrace(scriptConsole.err);
        }
        return false;
    }

    /**
     * 格式化内容.
     *
     * @param template 模板.
     * @param args     参数.
     * @return 结果.
     */
    public static String format(String template, Object... args) {
        return String.format(template, args);
    }


    /**
     * 获取字符串，开始结束字符串.
     *
     * @param src   原始字符串.
     * @param start 开始字符串.
     * @param end   结束字符器.
     * @return 字符串列表.
     */
    public static String getStrFromTo(String src, String start, String end) {
        if (isBlank(src)) {
            return null;
        }
        int i = src.indexOf(start);
        if (i < 0) {
            return null;
        }
        src = src.substring(i + start.length());
        if (null != end) {
            if (!src.contains(end)) {
                throw new IllegalArgumentException("end[" + end + "] not contains on src[" + src + "]");
            }
            return src.substring(0, src.indexOf(end));
        }
        return src;
    }

    /**
     * 数据交换.主要用于tcp协议的交换
     *
     * @param in  输入流
     * @param out 输出流
     */
    public static void transfer(final InputStream in, final OutputStream out) {
        byte[] bytes = new byte[1024];
        int n;
        try {
            while ((n = in.read(bytes)) > -1) {
                out.write(bytes, 0, n);
                out.flush();
            }
        } catch (Exception ignored) {
        }
    }
}
